import os
import json
import zipfile


def sys_exec(fmt, *args):
    cmd = fmt.format(*args)
    print(cmd)
    os.system(cmd)


def solve_path(*args):
    if len(args) > 1:
        return os.path.join(*args)
    args = args[0]
    if isinstance(args, (tuple, list)):
        return os.path.join(*args)
    return args


def exists(*args):
    path = solve_path(*args)
    return os.path.exists(path)


def split(*args):
    full = solve_path(*args)
    base = os.path.dirname(full)
    name = os.path.basename(full)
    return name, base


def mkdir(*paths):
    path = solve_path(*paths)
    if not os.path.exists(path):
        sys_exec('''mkdir -p "{}"''', path)


def prepare_dir(*paths, clear=False):
    path = solve_path(*paths)
    path = os.path.dirname(path)
    if os.path.exists(path):
        if clear:
            sys_exec('''rm -rf "{}"/*''', path)
    else:
        sys_exec('''mkdir -p "{}"''', path)


def rm(*paths):
    path = solve_path(*paths)
    if os.path.exists(path):
        sys_exec('''rm -rf "{}"''', path)


def rm_(*paths):
    path = solve_path(*paths)
    if os.path.exists(path):
        sys_exec('''rm -rf "{}"/*''', path)


def cp(src, dst):
    src = solve_path(src)
    dst = solve_path(dst)
    sys_exec('''cp -rf "{}" "{}"''', src, dst)


def cp_(src, dst):
    src = solve_path(src)
    dst = solve_path(dst)
    prepare_dir(dst, "*", clear=True)
    sys_exec('''cp -rf "{}"/* "{}"/''', src, dst)


def mv(src, dst):
    src = solve_path(src)
    dst = solve_path(dst)
    rm(dst)
    sys_exec('''mv "{}" "{}"''', src, dst)


def r_data(*paths):
    with open(solve_path(*paths), "r") as file:
        return file.read()


def w_data(data, *paths):
    with open(solve_path(*paths), "w") as file:
        return file.write(data)


def r_line(*paths):
    with open(solve_path(*paths), "r") as file:
        return file.readlines()


def w_line(lines, *paths, break_line=True):
    data = ("\n" if break_line else "").join(lines)
    with open(solve_path(*paths), "w") as file:
        return file.write(data)


def r_json(*paths):
    with open(solve_path(*paths), "r") as file:
        return json.load(file)


def w_json(data, *paths):
    with open(solve_path(*paths), "w") as file:
        data = json.dumps(data, indent=4, ensure_ascii=False)
        return file.write(data)


def uzp(src, dst):
    src = solve_path(src)
    dst = solve_path(dst)
    if not zipfile.is_zipfile(src):
        raise Exception("'{}'不是zip文件".format(src))
    if dst is None:
        dst = src[:-4] if src.endswith(".zip") else src + "_"
    prepare_dir(dst, "*", clear=True)
    with zipfile.ZipFile(src, "r") as zip_file:
        for file in zip_file.namelist():
            print("Extracting", file)
            zip_file.extract(file, dst)


def zip(src, dst,
        ignore_dir=lambda path: os.path.basename(path).startswith(".") or path.endswith("__MACOSX"),
        ignore_file=lambda name: name.startswith(".")):
    src = solve_path(src)
    dst = solve_path(dst)
    if not os.path.isdir(src):
        raise Exception("'{}'不是一个目录".format(src))
    if dst is None:
        dst = src
    if not dst.endswith(".zip"):
        dst += ".zip"
    prepare_dir(dst)
    with zipfile.ZipFile(dst, "w", zipfile.ZIP_DEFLATED, strict_timestamps=False) as zip_file:
        for parent_path, dir_names, filenames in os.walk(src):
            parent_name = os.path.basename(parent_path)
            if ignore_dir(parent_name):
                continue
            parent_path_zip = parent_path.replace(src, "")
            for filename in filenames:
                if ignore_file(filename):
                    continue
                src_path = os.path.join(parent_path, filename)
                dst_path = os.path.join(parent_path_zip, filename)
                print("Packing", dst_path)
                zip_file.write(src_path, dst_path)


class SuffixFilter:

    def __init__(self, suffix_set):
        self.set = suffix_set

    def __call__(self, *args, **kwargs):
        name = args[0]
        index = name.rfind(".")
        if index < 0:
            return False
        suffix = name[index + 1:]
        return suffix in self.set


class NameFilter:

    def __init__(self, name_set):
        self.set = name_set

    def __call__(self, *args, **kwargs):
        return args[0] in self.set


def filter_dir(root_path, filters, callback):
    for parent_path, dir_names, filenames in os.walk(root_path):
        if os.path.basename(parent_path).startswith("."):
            continue
        for filename in filenames:
            if filename.startswith("."):
                continue
            for file_filter in filters:
                if file_filter(filename):
                    break
            else:
                continue
            full_path = os.path.join(parent_path, filename)
            if callback(full_path, parent_path, filename):
                return


def rename_files(entries):
    for entry in entries:
        root_path = entry[0]

        def callback(src, dirname, old_filename):
            new_filename = old_filename.replace(entry[1], entry[2])
            if new_filename != old_filename:
                dst = os.path.join(dirname, new_filename)
                sys_exec('''mv "{}" "{}"''', src, dst)

        filter_dir(root_path, [], callback)

